Attaching package: ‘dplyr’

The following objects are masked from ‘package:stats’:

    filter, lag

The following objects are masked from ‘package:base’:

    intersect, setdiff, setequal, union

Registered S3 methods overwritten by 'dbplyr':
  method         from
  print.tbl_lazy     
  print.tbl_sql      
── Attaching packages ────────────────────────────────────────────────────────────────────────────────────── tidyverse 1.3.1 ──
✓ tibble  3.1.6     ✓ purrr   0.3.4
✓ tidyr   1.1.4     ✓ forcats 0.5.1
✓ readr   2.0.2     
── Conflicts ───────────────────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
x tidyr::extract()   masks magrittr::extract()
x dplyr::filter()    masks stats::filter()
x dplyr::lag()       masks stats::lag()
x purrr::set_names() masks magrittr::set_names()

Attaching package: ‘jsonlite’

The following object is masked from ‘package:purrr’:

    flatten

Loading required package: NLP

Attaching package: ‘NLP’

The following object is masked from ‘package:ggplot2’:

    annotate

Package version: 3.2.0
Unicode version: 13.0
ICU version: 69.1
Parallel computing: 8 of 8 threads used.
See https://quanteda.io for tutorials and examples.

Attaching package: ‘quanteda’

The following object is masked from ‘package:tm’:

    stopwords

The following objects are masked from ‘package:NLP’:

    meta, meta<-


Attaching package: ‘rvest’

The following object is masked from ‘package:readr’:

    guess_encoding

Loading required package: RColorBrewer

‘network’ 1.17.1 (2021-06-12), part of the Statnet Project
* ‘news(package="network")’ for changes since last version
* ‘citation("network")’ for citation information
* ‘https://statnet.org’ for help, support, and other information


Attaching package: ‘igraph’

The following objects are masked from ‘package:network’:

    %c%, %s%, add.edges, add.vertices, delete.edges, delete.vertices, get.edge.attribute, get.edges,
    get.vertex.attribute, is.bipartite, is.directed, list.edge.attributes, list.vertex.attributes,
    set.edge.attribute, set.vertex.attribute

The following object is masked from ‘package:formattable’:

    normalize

The following objects are masked from ‘package:purrr’:

    compose, simplify

The following object is masked from ‘package:tidyr’:

    crossing

The following object is masked from ‘package:tibble’:

    as_data_frame

The following objects are masked from ‘package:dplyr’:

    as_data_frame, groups, union

The following objects are masked from ‘package:stats’:

    decompose, spectrum

The following object is masked from ‘package:base’:

    union

Network visualization using output from text model

Data preparation

edgelist <- read.csv("../../../Data/Text_Model_Data/edgelist.csv")
edgelist

Indicator title

indicator_info <- read.csv("../../../Data/Text_Model_Data/indicator_att.csv")
library(stringr)
str_replace_all(indicator_info$Indicator, fixed(" "), "")
Textdata <- datatable(indicator_info, rownames=TRUE, caption=htmltools::tags$caption(style="caption-side: bottom; text-align: center;", "Innovative counties in the U.S."), filter="top", extensions="Buttons", options=list(dom = "Bfrtip", buttons = c("colvis", "copy", "csv", "excel", "pdf", "print")))
Textdata

For future classification of indicators into the goals they belong to, create the nodes dataframe:

nodes <- edgelist %>%
  select(indicator, related_indicator)
nodes <- data.frame(Indicator = unlist(nodes, use.names = FALSE))
nodes <- distinct(nodes)
str_replace_all(nodes$Indicator, fixed(" "), "")
  [1] "1.1.1"   "1.2.2"   "1.3.1"   "1.4.1"   "1.4.2"   "1.5.1"   "1.5.2"   "1.5.3"   "1.5.4"   "1.a.1"   "1.a.2"   "2.2.1"  
 [13] "2.2.2"   "2.2.3"   "2.3.1"   "2.3.2"   "2.4.1"   "2.5.1"   "2.5.2"   "2.a.1"   "2.a.2"   "2.b.1"   "2.c.1"   "3.1.1"  
 [25] "3.2.1"   "3.3.1"   "3.3.2"   "3.4.1"   "3.4.2"   "3.6.1"   "3.7.2"   "3.8.2"   "3.9.2"   "3.b.2"   "4.1.1"   "4.1.2"  
 [37] "4.2.1"   "4.2.2"   "4.3.1"   "4.6.1"   "4.7.1"   "4.a.1"   "4.b.1"   "4.c.1"   "5.2.1"   "5.2.2"   "5.3.1"   "5.4.1"  
 [49] "5.6.1"   "5.6.2"   "5.a.1"   "5.a.2"   "5.b.1"   "6.1.1"   "6.3.2"   "6.4.1"   "6.4.2"   "6.5.2"   "6.6.1"   "6.a.1"  
 [61] "6.b.1"   "7.1.1"   "7.2.1"   "7.3.1"   "7.a.1"   "7.b.1"   "8.1.1"   "8.2.1"   "8.3.1"   "8.4.1"   "8.4.2"   "8.5.1"  
 [73] "8.6.1"   "8.7.1"   "8.8.2"   "8.9.1"   "8.a.1"   "8.b.1"   "9.2.1"   "9.2.2"   "9.3.1"   "9.3.2"   "9.4.1"   "9.5.1"  
 [85] "9.5.2"   "9.a.1"   "9.b.1"   "10.1.1"  "10.3.1"  "10.6.1"  "10.7.1"  "10.7.4"  "10.a.1"  "10.b.1"  "11.1.1"  "11.3.1" 
 [97] "11.3.2"  "11.5.1"  "11.5.2"  "11.6.1"  "11.7.2"  "11.a.1"  "11.b.1"  "11.b.2"  "12.1.1"  "12.2.1"  "12.4.1"  "12.8.1" 
[109] "13.1.2"  "13.2.1"  "13.2.2"  "14.4.1"  "14.5.1"  "14.6.1"  "14.7.1"  "14.c.1"  "15.1.1"  "15.1.2"  "15.4.1"  "15.7.1" 
[121] "15.9.1"  "15.a.1"  "16.1.1"  "16.1.3"  "16.2.1"  "16.5.2"  "16.6.1"  "16.6.2"  "16.8.1"  "16.10.1" "16.10.2" "16.a.1" 
[133] "17.1.1"  "17.2.1"  "17.4.1"  "17.5.1"  "17.10.1" "17.11.1" "17.15.1" "17.18.2" "17.18.3" "1.2.1"   "1.b.1"   "6.2.1"  
[145] "11.2.1"  "9.1.1"   "3.8.1"   "15.3.1"  "16.b.1"  "14.b.1"  "13.1.1"  "12.3.1"  "13.1.3"  "17.12.1" "17.9.1"  "17.1.2" 
[157] "11.4.1"  "13.3.1"  "12.c.1"  "16.2.3"  "15.6.1"  "3.2.2"   "3.3.3"   "3.9.1"   "3.9.3"   "8.8.1"   "5.3.2"   "16.9.1" 
[169] "5.5.2"   "5.c.1"   "9.c.1"   "17.8.1"  "12.a.1"  "10.2.1"  "17.3.2"  "8.5.2"   "12.2.2"  "12.b.1"  "10.4.1"  "10.c.1" 
[181] "16.1.2"  "16.4.1"  "17.19.2" "12.4.2"  "17.14.1" "13.b.1"  "13.a.1"  "15.b.1"  "17.16.1" "15.2.1"  "15.4.2"  "15.c.1" 
[193] "16.3.1"  "16.3.3"  "16.7.2"  "17.19.1"
#nodes$goal <- stri_match_first_regex(nodes$indicator, "(.*?)\\.")[,2]
#nodes$goal <-as.numeric(nodes$goal)
nodes<-merge(x=nodes,y=indicator_info,by="Indicator",all.x=TRUE)
g<-graph_from_data_frame(edgelist, directed=FALSE, vertices=nodes)
in_degree<-degree(g, mode="in")
in_degree<-as.data.frame(in_degree)
in_degree <- cbind(rownames(in_degree), in_degree)
rownames(in_degree) <- NULL
colnames(in_degree) <- c("Indicator","in_degree")
str_replace_all(in_degree$Indicator, fixed(" "), "")
  [1] "1.1.1"   "1.2.1"   "1.2.2"   "1.3.1"   "1.4.1"   "1.4.2"   "1.5.1"   "1.5.2"   "1.5.3"   "1.5.4"   "1.a.1"   "1.a.2"  
 [13] "1.b.1"   "10.1.1"  "10.2.1"  "10.3.1"  "10.4.1"  "10.6.1"  "10.7.1"  "10.7.4"  "10.a.1"  "10.b.1"  "10.c.1"  "11.1.1" 
 [25] "11.2.1"  "11.3.1"  "11.3.2"  "11.4.1"  "11.5.1"  "11.5.2"  "11.6.1"  "11.7.2"  "11.a.1"  "11.b.1"  "11.b.2"  "12.1.1" 
 [37] "12.2.1"  "12.2.2"  "12.3.1"  "12.4.1"  "12.4.2"  "12.8.1"  "12.a.1"  "12.b.1"  "12.c.1"  "13.1.1"  "13.1.2"  "13.1.3" 
 [49] "13.2.1"  "13.2.2"  "13.3.1"  "13.a.1"  "13.b.1"  "14.4.1"  "14.5.1"  "14.6.1"  "14.7.1"  "14.b.1"  "14.c.1"  "15.1.1" 
 [61] "15.1.2"  "15.2.1"  "15.3.1"  "15.4.1"  "15.4.2"  "15.6.1"  "15.7.1"  "15.9.1"  "15.a.1"  "15.b.1"  "15.c.1"  "16.1.1" 
 [73] "16.1.2"  "16.1.3"  "16.10.1" "16.10.2" "16.2.1"  "16.2.3"  "16.3.1"  "16.3.3"  "16.4.1"  "16.5.2"  "16.6.1"  "16.6.2" 
 [85] "16.7.2"  "16.8.1"  "16.9.1"  "16.a.1"  "16.b.1"  "17.1.1"  "17.1.2"  "17.10.1" "17.11.1" "17.12.1" "17.14.1" "17.15.1"
 [97] "17.16.1" "17.18.2" "17.18.3" "17.19.1" "17.19.2" "17.2.1"  "17.3.2"  "17.4.1"  "17.5.1"  "17.8.1"  "17.9.1"  "2.2.1"  
[109] "2.2.2"   "2.2.3"   "2.3.1"   "2.3.2"   "2.4.1"   "2.5.1"   "2.5.2"   "2.a.1"   "2.a.2"   "2.b.1"   "2.c.1"   "3.1.1"  
[121] "3.2.1"   "3.2.2"   "3.3.1"   "3.3.2"   "3.3.3"   "3.4.1"   "3.4.2"   "3.6.1"   "3.7.2"   "3.8.1"   "3.8.2"   "3.9.1"  
[133] "3.9.2"   "3.9.3"   "3.b.2"   "4.1.1"   "4.1.2"   "4.2.1"   "4.2.2"   "4.3.1"   "4.6.1"   "4.7.1"   "4.a.1"   "4.b.1"  
[145] "4.c.1"   "5.2.1"   "5.2.2"   "5.3.1"   "5.3.2"   "5.4.1"   "5.5.2"   "5.6.1"   "5.6.2"   "5.a.1"   "5.a.2"   "5.b.1"  
[157] "5.c.1"   "6.1.1"   "6.2.1"   "6.3.2"   "6.4.1"   "6.4.2"   "6.5.2"   "6.6.1"   "6.a.1"   "6.b.1"   "7.1.1"   "7.2.1"  
[169] "7.3.1"   "7.a.1"   "7.b.1"   "8.1.1"   "8.2.1"   "8.3.1"   "8.4.1"   "8.4.2"   "8.5.1"   "8.5.2"   "8.6.1"   "8.7.1"  
[181] "8.8.1"   "8.8.2"   "8.9.1"   "8.a.1"   "8.b.1"   "9.1.1"   "9.2.1"   "9.2.2"   "9.3.1"   "9.3.2"   "9.4.1"   "9.5.1"  
[193] "9.5.2"   "9.a.1"   "9.b.1"   "9.c.1"  
nodes<-merge(x=nodes,y=in_degree,by="Indicator",all.x=TRUE)
nodes<-nodes %>%
  select(Indicator, Goal, Indicator_title, in_degree)
nodes

Visualization

In the network graph below, the size of each vertices (each indicator) represents the number of related indicators that are connected to it. The width of the edges linking each indicator is determined according to the similarity score between each pair of related indicators. The indicators are grouped according to the goals they belong to, which are denoted by different colors of the vertices.


edges <- edgelist %>% dplyr::rename(Indicator = indicator)

nodes <- data.frame(id = nodes$Indicator,
                    label = nodes$Indicator,
                    group = nodes$Goal,
                    color = ifelse(nodes$Goal == 1,"#ea1d2d",ifelse(nodes$Goal == 2,"#d19f2a",ifelse(nodes$Goal == 3,"#2d9a47",
                            ifelse(nodes$Goal == 4,"#c22033",ifelse(nodes$Goal == 5,"#ef412a",ifelse(nodes$Goal == 6,"#00add8",
                            ifelse(nodes$Goal == 7,"#fdb714",ifelse(nodes$Goal == 8,"#8f1838",ifelse(nodes$Goal == 9,"#f36e24",
                            ifelse(nodes$Goal == 10,"#e01a83",ifelse(nodes$Goal == 11,"#f99d25",ifelse(nodes$Goal == 12,"#cd8b2a",
                            ifelse(nodes$Goal == 13,"#48773c",ifelse(nodes$Goal == 14,"#007dbb",ifelse(nodes$Goal == 15,"#40ae49",
                            ifelse(nodes$Goal == 16,"#00558a","#1a3668")))))))))))))))),
                    highlight = ifelse(nodes$Goal == 1,"#ea1d2d",ifelse(nodes$Goal == 2,"#d19f2a",ifelse(nodes$Goal == 3,"#2d9a47",
                            ifelse(nodes$Goal == 4,"#c22033",ifelse(nodes$Goal == 5,"#ef412a",ifelse(nodes$Goal == 6,"#00add8",
                            ifelse(nodes$Goal == 7,"#fdb714",ifelse(nodes$Goal == 8,"#8f1838",ifelse(nodes$Goal == 9,"#f36e24",
                            ifelse(nodes$Goal == 10,"#e01a83",ifelse(nodes$Goal == 11,"#f99d25",ifelse(nodes$Goal == 12,"#cd8b2a",
                            ifelse(nodes$Goal == 13,"#48773c",ifelse(nodes$Goal == 14,"#007dbb",ifelse(nodes$Goal == 15,"#40ae49",
                            ifelse(nodes$Goal == 16,"#00558a","#1a3668")))))))))))))))),
                    size = nodes$in_degree*10)

edges <- data.frame(from = edges$Indicator, to=edges$related_indicator, width = edges$similarity_score*4, color='gray')

nodes$shape  <- "dot"  
nodes$shadow <- FALSE

# this section doesn't allow our graph to show up - no idea why. 
# nodes$color.background <- nodes$color 
# nodes$color.border <- nodes$color 
# nodes$color.highlight.background <- nodes$color 
# nodes$color.highlight.border <- nodes$color 


edges$color <- "gray"    # line color  
edges$smooth <- FALSE    # should the edges be curved?
edges$shadow <- FALSE

visnet<-visNetwork(nodes,edges, height = "700px", width = "100%", main="Text Network Model",submain= "UN SDG Indicator Metadata", footer="Zoom in to see indicator name, click/hover to see indicator title") %>%
    visEdges(smooth = FALSE) %>%

  visOptions(selectedBy = "Goal", 
             highlightNearest = TRUE, 
             nodesIdSelection = TRUE) #%>%
  #visLegend(main="Legend",position="right", ncol=1)
visnet
visSave(visnet, file = "Text Network Model.html")

Network visualization using output from the social network model

Indonesia

###Data preparation

edgelistindo <- read.csv("~/Documents/GitHub/G5055_Practicum_Project2/Data/PCA_results/indo_coefficients_sig.csv")
#Some preprocessing
edgelistindo<-edgelistindo%>%
  select(Var1, Var2, value)%>%
  filter(Var1!=Var2)
names(edgelistindo)<-c("from","to","value")
edgelistindo

For future classification of indicators into the goals they belong to, create the nodes dataframe:

indonodes <- edgelistindo %>%
  select(from, to)
indonodes <- data.frame(Indicator = unlist(indonodes, use.names = FALSE))
indonodes <- distinct(indonodes)
#indonodes$goal <- stri_match_first_regex(indonodes$indicator, "(.*?)\\.")[,2]
#indonodes$goal <-as.numeric(indonodes$goal)
indonodes<-merge(x=indonodes,y=indicator_info,by="Indicator",all.x=TRUE)
g2<-graph_from_data_frame(edgelistindo, directed=FALSE, vertices=indonodes)
in_degree<-degree(g2, mode="in")
in_degree<-as.data.frame(in_degree)
in_degree <- cbind(rownames(in_degree), in_degree)
rownames(in_degree) <- NULL
colnames(in_degree) <- c("Indicator","in_degree")
indonodes<-merge(x=indonodes,y=in_degree,by="Indicator",all.x=TRUE)
indonodes<-indonodes %>%
  arrange(Goal)
indonodes<-indonodes %>%
  select(Indicator, Goal, Indicator_title, in_degree)
indonodes
indonodes

Visualization

indicator_info <- read.csv("../../../Data/Text_Model_Data/indicator_att.csv")
library(stringr)
str_replace_all(indicator_info$Indicator, fixed(" "), "")
  [1] "1.1.1"   "1.2.1"   "1.2.2"   "1.3.1"   "1.4.1"   "1.4.2"   "1.5.1"   "1.5.2"   "1.5.3"   "1.5.4"   "1.a.1"   "1.a.2"  
 [13] "1.b.1"   "2.1.1"   "2.1.2"   "2.2.1"   "2.2.2"   "2.2.3"   "2.3.1"   "2.3.2"   "2.4.1"   "2.5.1"   "2.5.2"   "2.a.1"  
 [25] "2.a.2"   "2.b.1"   "2.c.1"   "3.1.1"   "3.1.2"   "3.2.1"   "3.2.2"   "3.3.1"   "3.3.2"   "3.3.3"   "3.3.4"   "3.3.5"  
 [37] "3.4.1"   "3.4.2"   "3.5.1"   "3.5.2"   "3.6.1"   "3.7.1"   "3.7.2"   "3.8.1"   "3.8.2"   "3.9.1"   "3.9.2"   "3.9.3"  
 [49] "3.a.1"   "3.b.1"   "3.b.2"   "3.b.3"   "3.c.1"   "3.d.1"   "3.d.2"   "4.1.1"   "4.1.2"   "4.2.1"   "4.2.2"   "4.3.1"  
 [61] "4.4.1"   "4.5.1"   "4.6.1"   "4.7.1"   "4.a.1"   "4.b.1"   "4.c.1"   "5.1.1"   "5.2.1"   "5.2.2"   "5.3.1"   "5.3.2"  
 [73] "5.4.1"   "5.5.1"   "5.5.2"   "5.6.1"   "5.6.2"   "5.a.1"   "5.a.2"   "5.b.1"   "5.c.1"   "6.1.1"   "6.2.1"   "6.3.1"  
 [85] "6.3.2"   "6.4.1"   "6.4.2"   "6.5.1"   "6.5.2"   "6.6.1"   "6.a.1"   "6.b.1"   "7.1.1"   "7.1.2"   "7.2.1"   "7.3.1"  
 [97] "7.a.1"   "7.b.1"   "8.1.1"   "8.2.1"   "8.3.1"   "8.4.1"   "8.4.2"   "8.5.1"   "8.5.2"   "8.6.1"   "8.7.1"   "8.8.1"  
[109] "8.8.2"   "8.9.1"   "8.10.1"  "8.10.2"  "8.a.1"   "8.b.1"   "9.1.1"   "9.1.2"   "9.2.1"   "9.2.2"   "9.3.1"   "9.3.2"  
[121] "9.4.1"   "9.5.1"   "9.5.2"   "9.a.1"   "9.b.1"   "9.c.1"   "10.1.1"  "10.2.1"  "10.3.1"  "10.4.1"  "10.4.2"  "10.5.1" 
[133] "10.6.1"  "10.7.1"  "10.7.2"  "10.7.3"  "10.7.4"  "10.a.1"  "10.b.1"  "10.c.1"  "11.1.1"  "11.2.1"  "11.3.1"  "11.3.2" 
[145] "11.4.1"  "11.5.1"  "11.5.2"  "11.6.1"  "11.6.2"  "11.7.1"  "11.7.2"  "11.a.1"  "11.b.1"  "11.b.2"  "12.1.1"  "12.2.1" 
[157] "12.2.2"  "12.3.1"  "12.4.1"  "12.4.2"  "12.5.1"  "12.6.1"  "12.7.1"  "12.8.1"  "12.a.1"  "12.b.1"  "12.c.1"  "13.1.1" 
[169] "13.1.2"  "13.1.3"  "13.2.1"  "13.2.2"  "13.3.1"  "13.a.1"  "13.b.1"  "14.1.1"  "14.2.1"  "14.3.1"  "14.4.1"  "14.5.1" 
[181] "14.6.1"  "14.7.1"  "14.a.1"  "14.b.1"  "14.c.1"  "15.1.1"  "15.1.2"  "15.2.1"  "15.3.1"  "15.4.1"  "15.4.2"  "15.5.1" 
[193] "15.6.1"  "15.7.1"  "15.8.1"  "15.9.1"  "15.a.1"  "15.b.1"  "15.c.1"  "16.1.1"  "16.1.2"  "16.1.3"  "16.1.4"  "16.2.1" 
[205] "16.2.2"  "16.2.3"  "16.3.1"  "16.3.2"  "16.3.3"  "16.4.1"  "16.4.2"  "16.5.1"  "16.5.2"  "16.6.1"  "16.6.2"  "16.7.1" 
[217] "16.7.2"  "16.8.1"  "16.9.1"  "16.10.1" "16.10.2" "16.a.1"  "16.b.1"  "17.1.1"  "17.1.2"  "17.2.1"  "17.3.1"  "17.3.2" 
[229] "17.4.1"  "17.5.1"  "17.6.1"  "17.7.1"  "17.8.1"  "17.9.1"  "17.10.1" "17.11.1" "17.12.1" "17.13.1" "17.14.1" "17.15.1"
[241] "17.16.1" "17.17.1" "17.18.2" "17.18.3" "17.19.1" "17.19.2"
Textdata <- datatable(indicator_info, rownames=TRUE, caption=htmltools::tags$caption(style="caption-side: bottom; text-align: center;", "Innovative counties in the U.S."), filter="top", extensions="Buttons", options=list(dom = "Bfrtip", buttons = c("colvis", "copy", "csv", "excel", "pdf", "print")))
Textdata

Guatemala (Not finished)

Data preparation

edgelistguate <- read.csv("~/Documents/GitHub/G5055_Practicum_Project2/Data/PCA_results/gua_coefficients_sig.csv")
#Some preprocessing
edgelistguate<-edgelistguate%>%
  select(Var1, Var2, value)%>%
  filter(Var1!=Var2)
names(edgelistindo)<-c("from","to","value")
edgelistguate

Visualization

guatenodes <- edgelistguate %>%
  select(Var1, Var2)
guatenodes <- data.frame(indicatorname = unlist(guatenodes, use.names = FALSE))
guatenodes <- distinct(guatenodes)
#guatenodes$goal <- stri_match_first_regex(guatenodes$indicator, "(.*?)\\.")[,2]
#guatenodes$goal <-as.numeric(guatenodes$goal)
g3<-graph_from_data_frame(edgelistguate, directed=FALSE, vertices=guatenodes)
guatenodes
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKLS0tCnRpdGxlOiAiSW50ZXJhY3RpdmUgTmV0d29ya3MiCmF1dGhvcjogIkxpIFBlaXNoYW4iCmRhdGU6ICIxMS8yMy8yMDIxIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogeWVzCiAgICB0aGVtZTogam91cm5hbAotLS0KPHN0eWxlPgpib2R5eyAvKiBOb3JtYWwgKi8KZm9udC1zaXplOiAxNXB4Owpjb2xvcjogYmxhY2s7Cn0Kd3JpdGUgeyAgCmxpbmUtaGVpZ2h0OiA3ZW07Cn0KdGFibGUgeyAvKiBUYWJsZSAqLwpmb250LXNpemU6IDEycHg7Cn0KaDEgeyAvKiBIZWFkZXIgMSAqLwpmb250LXNpemU6IDMwcHg7Cn0KaDIgeyAvKiBIZWFkZXIgMiAqCmZvbnQtc2l6ZTogMjZweDsKfQpoMyB7IC8qIEhlYWRlciAzICovCmZvbnQtc2l6ZTogMjJweDsKfQpjb2RlLnJ7IC8qIENvZGUgYmxvY2sgKi8KZm9udC1zaXplOiAxNHB4Owp9CnByZSB7IC8qIENvZGUgYmxvY2sgKi8KZm9udC1zaXplOiAxNHB4Cn0KLm1haW4tY29udGFpbmVyIHsKICAgIHdpZHRoOiA4MCU7CiAgICBtYXgtd2lkdGg6IHVuc2V0Owp9Cjwvc3R5bGU+CgpgYGB7ciBzZXR1cCwgZWNobz1GQUxTRSwgZXZhbD1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsZXZhbD1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFKQpgYGAKCmBgYHtyIGxvYWQgcGFja2FnZXMsIGVjaG89RkFMU0UsIGV2YWw9VFJVRX0KbGlicmFyeShyZWFkeGwpCmxpYnJhcnkobWFncml0dHIpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZ2dwbG90MikgICAgCmxpYnJhcnkoZ2d0aGVtZXMpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGpzb25saXRlKQpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KHRpZHl0ZXh0KQpsaWJyYXJ5KHRleHRkYXRhKQpsaWJyYXJ5KHRtKQpsaWJyYXJ5KHF1YW50ZWRhKQpsaWJyYXJ5KHJ2ZXN0KQpsaWJyYXJ5KHN0cmluZ3IpCmxpYnJhcnkoU25vd2JhbGxDKQpsaWJyYXJ5KHdvcmRjbG91ZCkKbGlicmFyeShwbG90cml4KQpsaWJyYXJ5KHFkYXBEaWN0aW9uYXJpZXMpCmxpYnJhcnkoZm9ybWF0dGFibGUpCmxpYnJhcnkoc3RyaW5ncikKbGlicmFyeShEVCkKbGlicmFyeShuZXR3b3JrKQpsaWJyYXJ5KGdnbmV0d29yaykKbGlicmFyeShpZ3JhcGgpCmxpYnJhcnkoUkNvbG9yQnJld2VyKQpsaWJyYXJ5KHJhbmRvbWNvbG9SKQpsaWJyYXJ5KHN0cmluZ2kpCmxpYnJhcnkoaWdyYXBoKQpsaWJyYXJ5KGdncmFwaCkKbGlicmFyeShncmFwaGxheW91dHMpCmxpYnJhcnkodmlzTmV0d29yaykKYGBgCiMgTmV0d29yayB2aXN1YWxpemF0aW9uIHVzaW5nIG91dHB1dCBmcm9tIHRleHQgbW9kZWwKIyMgRGF0YSBwcmVwYXJhdGlvbgpgYGB7ciBpbXBvcnQgZGF0YSwgZWNobz1UUlVFLCBldmFsPVRSVUV9CmVkZ2VsaXN0IDwtIHJlYWQuY3N2KCIuLi8uLi8uLi9EYXRhL1RleHRfTW9kZWxfRGF0YS9lZGdlbGlzdC5jc3YiKQplZGdlbGlzdApgYGAKSW5kaWNhdG9yIHRpdGxlCmBgYHtyLCB0ZXh0IHRpdGxlcywgZWNobz1UUlVFLCBldmFsPVRSVUV9CmluZGljYXRvcl9pbmZvIDwtIHJlYWQuY3N2KCIuLi8uLi8uLi9EYXRhL1RleHRfTW9kZWxfRGF0YS9pbmRpY2F0b3JfYXR0LmNzdiIpCmxpYnJhcnkoc3RyaW5ncikKc3RyX3JlcGxhY2VfYWxsKGluZGljYXRvcl9pbmZvJEluZGljYXRvciwgZml4ZWQoIiAiKSwgIiIpClRleHRkYXRhIDwtIGRhdGF0YWJsZShpbmRpY2F0b3JfaW5mbywgcm93bmFtZXM9VFJVRSwgY2FwdGlvbj1odG1sdG9vbHM6OnRhZ3MkY2FwdGlvbihzdHlsZT0iY2FwdGlvbi1zaWRlOiBib3R0b207IHRleHQtYWxpZ246IGNlbnRlcjsiLCAiSW5ub3ZhdGl2ZSBjb3VudGllcyBpbiB0aGUgVS5TLiIpLCBmaWx0ZXI9InRvcCIsIGV4dGVuc2lvbnM9IkJ1dHRvbnMiLCBvcHRpb25zPWxpc3QoZG9tID0gIkJmcnRpcCIsIGJ1dHRvbnMgPSBjKCJjb2x2aXMiLCAiY29weSIsICJjc3YiLCAiZXhjZWwiLCAicGRmIiwgInByaW50IikpKQpUZXh0ZGF0YQpgYGAKRm9yIGZ1dHVyZSBjbGFzc2lmaWNhdGlvbiBvZiBpbmRpY2F0b3JzIGludG8gdGhlIGdvYWxzIHRoZXkgYmVsb25nIHRvLCBjcmVhdGUgdGhlIG5vZGVzIGRhdGFmcmFtZToKYGBge3IgY3JlYXRlIG5vZGVzLCBlY2hvPVRSVUUsIGV2YWw9VFJVRX0Kbm9kZXMgPC0gZWRnZWxpc3QgJT4lCiAgc2VsZWN0KGluZGljYXRvciwgcmVsYXRlZF9pbmRpY2F0b3IpCm5vZGVzIDwtIGRhdGEuZnJhbWUoSW5kaWNhdG9yID0gdW5saXN0KG5vZGVzLCB1c2UubmFtZXMgPSBGQUxTRSkpCm5vZGVzIDwtIGRpc3RpbmN0KG5vZGVzKQpzdHJfcmVwbGFjZV9hbGwobm9kZXMkSW5kaWNhdG9yLCBmaXhlZCgiICIpLCAiIikKI25vZGVzJGdvYWwgPC0gc3RyaV9tYXRjaF9maXJzdF9yZWdleChub2RlcyRpbmRpY2F0b3IsICIoLio/KVxcLiIpWywyXQojbm9kZXMkZ29hbCA8LWFzLm51bWVyaWMobm9kZXMkZ29hbCkKbm9kZXM8LW1lcmdlKHg9bm9kZXMseT1pbmRpY2F0b3JfaW5mbyxieT0iSW5kaWNhdG9yIixhbGwueD1UUlVFKQpnPC1ncmFwaF9mcm9tX2RhdGFfZnJhbWUoZWRnZWxpc3QsIGRpcmVjdGVkPUZBTFNFLCB2ZXJ0aWNlcz1ub2RlcykKaW5fZGVncmVlPC1kZWdyZWUoZywgbW9kZT0iaW4iKQppbl9kZWdyZWU8LWFzLmRhdGEuZnJhbWUoaW5fZGVncmVlKQppbl9kZWdyZWUgPC0gY2JpbmQocm93bmFtZXMoaW5fZGVncmVlKSwgaW5fZGVncmVlKQpyb3duYW1lcyhpbl9kZWdyZWUpIDwtIE5VTEwKY29sbmFtZXMoaW5fZGVncmVlKSA8LSBjKCJJbmRpY2F0b3IiLCJpbl9kZWdyZWUiKQpzdHJfcmVwbGFjZV9hbGwoaW5fZGVncmVlJEluZGljYXRvciwgZml4ZWQoIiAiKSwgIiIpCm5vZGVzPC1tZXJnZSh4PW5vZGVzLHk9aW5fZGVncmVlLGJ5PSJJbmRpY2F0b3IiLGFsbC54PVRSVUUpCm5vZGVzPC1ub2RlcyAlPiUKICBzZWxlY3QoSW5kaWNhdG9yLCBHb2FsLCBJbmRpY2F0b3JfdGl0bGUsIGluX2RlZ3JlZSkKbm9kZXMKYGBgCiMjIFZpc3VhbGl6YXRpb24KSW4gdGhlIG5ldHdvcmsgZ3JhcGggYmVsb3csIHRoZSBzaXplIG9mIGVhY2ggdmVydGljZXMgKGVhY2ggaW5kaWNhdG9yKSByZXByZXNlbnRzIHRoZSBudW1iZXIgb2YgcmVsYXRlZCBpbmRpY2F0b3JzIHRoYXQgYXJlIGNvbm5lY3RlZCB0byBpdC4gVGhlIHdpZHRoIG9mIHRoZSBlZGdlcyBsaW5raW5nIGVhY2ggaW5kaWNhdG9yIGlzIGRldGVybWluZWQgYWNjb3JkaW5nIHRvIHRoZSBzaW1pbGFyaXR5IHNjb3JlIGJldHdlZW4gZWFjaCBwYWlyIG9mIHJlbGF0ZWQgaW5kaWNhdG9ycy4gVGhlIGluZGljYXRvcnMgYXJlIGdyb3VwZWQgYWNjb3JkaW5nIHRvIHRoZSBnb2FscyB0aGV5IGJlbG9uZyB0bywgd2hpY2ggYXJlIGRlbm90ZWQgYnkgZGlmZmVyZW50IGNvbG9ycyBvZiB0aGUgdmVydGljZXMuCmBgYHtyIFN0YXRpYyBuZXR3b3JrIGZyb20gdGV4dCwgZmlnLndpZHRoPTE1LCBmaWcuaGVpZ2h0PTE1LCBlY2hvPUZBTFNFLCBldmFsPUZBTFNFfQpnPC1ncmFwaF9mcm9tX2RhdGFfZnJhbWUoZWRnZWxpc3QsIGRpcmVjdGVkPUZBTFNFLCB2ZXJ0aWNlcz1ub2RlcykKI0FkZCBhdHRyaWJ1dGVzCkUoZykkd2VpZ2h0PC1FKGcpJHNpbWlsYXJpdHlfc2NvcmUKVihnKSRpbl9kZWdyZWU8LWRlZ3JlZShnLCBtb2RlPSJpbiIpCmNvbHJzPC1jKCIjZWExZDJkIiwgIiNkMTlmMmEiLCIjMmQ5YTQ3IiwgIiNjMjIwMzMiLCIjZWY0MTJhIiwgIiMwMGFkZDkiLCAiI2ZkYjcxNCIsICIjOGYxODM4IiwgIiNmMzZlMjQiLCAiI2UwMWE4MyIsICIjZjk5ZDI1IiwgIiNjZDhiMmEiLCAiIzQ4NzczYyIsICIjMDA3ZGJiIiwgIiM0MGFlNDkiLCAgIiMwMDU1OGEiLCAiIzFhMzY2OCIpClYoZykkY29sb3I8LWNvbHJzW1YoZykkR29hbF0KI1Bsb3QgZ3JhcGgKcGxvdChnLCB2ZXJ0ZXgubGFiZWw9TkEsIGVkZ2UuY29sb3I9ImdyYXk3NyIsIHZlcnRleC5jb2xvcj1WKGcpJGNvbG9yLCB2ZXJ0ZXguc2l6ZT1WKGcpJGluX2RlZ3JlZSwgZWRnZS53aWR0aD1FKGcpJHdlaWdodCoxMCwgbGF5b3V0PWxheW91dF9uaWNlbHkoZykpCnBsb3QoZywgdmVydGV4LmxhYmVsLmNvbG9yPSJibGFjayIsIHZlcnRleC5sYWJlbC5jZXg9Mi41LCBlZGdlLmNvbG9yPSJncmF5NzciLCB2ZXJ0ZXguY29sb3I9VihnKSRjb2xvciwgdmVydGV4LnNpemU9VihnKSRpbl9kZWdyZWUsIGVkZ2Uud2lkdGg9RShnKSR3ZWlnaHQqMTAsIGxheW91dD1sYXlvdXRfbmljZWx5KGcpKQojbGVnZW5kKHg9LTExLCB5PS0xMSwgYygiR29hbCAxIiwiR29hbCAyIiwiR29hbCAzIiwiR29hbCA0IiwiR29hbCA1IiwiR29hbCA2IiwiR29hbCA3IiwiR29hbCA4IiwiR29hbCA5IiwiR29hbCAxMCIsIkdvYWwgMTEiLCAiR29hbCAxMiIsIkdvYWwgMTMiLCAiR29hbCAxNCIsICJHb2FsIDE1IiwgIkdvYWwgMTYiLCAiR29hbCAxNyIpLCBwY2g9MjAsIGNvbD0iIzc3Nzc3NyIsIHB0LmJnPWNvbHJzLCBwdC5jZXg9MiwgY2V4PS44LCBidHk9Im4iLCBuY29sPTEpCmBgYAoKYGBge3IsIEludGVyYWN0aXZlIFRleHQgTmV0d29yayBDb25uaWUsIGVjaG89VFJVRSwgZXZhbD1UUlVFfQoKZWRnZXMgPC0gZWRnZWxpc3QgJT4lIGRwbHlyOjpyZW5hbWUoSW5kaWNhdG9yID0gaW5kaWNhdG9yKQoKbm9kZXMgPC0gZGF0YS5mcmFtZShpZCA9IG5vZGVzJEluZGljYXRvciwKICAgICAgICAgICAgICAgICAgICBsYWJlbCA9IG5vZGVzJEluZGljYXRvciwKICAgICAgICAgICAgICAgICAgICBncm91cCA9IG5vZGVzJEdvYWwsCiAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBpZmVsc2Uobm9kZXMkR29hbCA9PSAxLCIjZWExZDJkIixpZmVsc2Uobm9kZXMkR29hbCA9PSAyLCIjZDE5ZjJhIixpZmVsc2Uobm9kZXMkR29hbCA9PSAzLCIjMmQ5YTQ3IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShub2RlcyRHb2FsID09IDQsIiNjMjIwMzMiLGlmZWxzZShub2RlcyRHb2FsID09IDUsIiNlZjQxMmEiLGlmZWxzZShub2RlcyRHb2FsID09IDYsIiMwMGFkZDgiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKG5vZGVzJEdvYWwgPT0gNywiI2ZkYjcxNCIsaWZlbHNlKG5vZGVzJEdvYWwgPT0gOCwiIzhmMTgzOCIsaWZlbHNlKG5vZGVzJEdvYWwgPT0gOSwiI2YzNmUyNCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2Uobm9kZXMkR29hbCA9PSAxMCwiI2UwMWE4MyIsaWZlbHNlKG5vZGVzJEdvYWwgPT0gMTEsIiNmOTlkMjUiLGlmZWxzZShub2RlcyRHb2FsID09IDEyLCIjY2Q4YjJhIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShub2RlcyRHb2FsID09IDEzLCIjNDg3NzNjIixpZmVsc2Uobm9kZXMkR29hbCA9PSAxNCwiIzAwN2RiYiIsaWZlbHNlKG5vZGVzJEdvYWwgPT0gMTUsIiM0MGFlNDkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKG5vZGVzJEdvYWwgPT0gMTYsIiMwMDU1OGEiLCIjMWEzNjY4IikpKSkpKSkpKSkpKSkpKSksCiAgICAgICAgICAgICAgICAgICAgaGlnaGxpZ2h0ID0gaWZlbHNlKG5vZGVzJEdvYWwgPT0gMSwiI2VhMWQyZCIsaWZlbHNlKG5vZGVzJEdvYWwgPT0gMiwiI2QxOWYyYSIsaWZlbHNlKG5vZGVzJEdvYWwgPT0gMywiIzJkOWE0NyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2Uobm9kZXMkR29hbCA9PSA0LCIjYzIyMDMzIixpZmVsc2Uobm9kZXMkR29hbCA9PSA1LCIjZWY0MTJhIixpZmVsc2Uobm9kZXMkR29hbCA9PSA2LCIjMDBhZGQ4IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShub2RlcyRHb2FsID09IDcsIiNmZGI3MTQiLGlmZWxzZShub2RlcyRHb2FsID09IDgsIiM4ZjE4MzgiLGlmZWxzZShub2RlcyRHb2FsID09IDksIiNmMzZlMjQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKG5vZGVzJEdvYWwgPT0gMTAsIiNlMDFhODMiLGlmZWxzZShub2RlcyRHb2FsID09IDExLCIjZjk5ZDI1IixpZmVsc2Uobm9kZXMkR29hbCA9PSAxMiwiI2NkOGIyYSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2Uobm9kZXMkR29hbCA9PSAxMywiIzQ4NzczYyIsaWZlbHNlKG5vZGVzJEdvYWwgPT0gMTQsIiMwMDdkYmIiLGlmZWxzZShub2RlcyRHb2FsID09IDE1LCIjNDBhZTQ5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShub2RlcyRHb2FsID09IDE2LCIjMDA1NThhIiwiIzFhMzY2OCIpKSkpKSkpKSkpKSkpKSkpLAogICAgICAgICAgICAgICAgICAgIHNpemUgPSBub2RlcyRpbl9kZWdyZWUqMTApCgplZGdlcyA8LSBkYXRhLmZyYW1lKGZyb20gPSBlZGdlcyRJbmRpY2F0b3IsIHRvPWVkZ2VzJHJlbGF0ZWRfaW5kaWNhdG9yLCB3aWR0aCA9IGVkZ2VzJHNpbWlsYXJpdHlfc2NvcmUqNCwgY29sb3I9J2dyYXknKQoKbm9kZXMkc2hhcGUgIDwtICJkb3QiICAKbm9kZXMkc2hhZG93IDwtIEZBTFNFCgojIHRoaXMgc2VjdGlvbiBkb2Vzbid0IGFsbG93IG91ciBncmFwaCB0byBzaG93IHVwIC0gbm8gaWRlYSB3aHkuIAojIG5vZGVzJGNvbG9yLmJhY2tncm91bmQgPC0gbm9kZXMkY29sb3IgCiMgbm9kZXMkY29sb3IuYm9yZGVyIDwtIG5vZGVzJGNvbG9yIAojIG5vZGVzJGNvbG9yLmhpZ2hsaWdodC5iYWNrZ3JvdW5kIDwtIG5vZGVzJGNvbG9yIAojIG5vZGVzJGNvbG9yLmhpZ2hsaWdodC5ib3JkZXIgPC0gbm9kZXMkY29sb3IgCgoKZWRnZXMkY29sb3IgPC0gImdyYXkiICAgICMgbGluZSBjb2xvciAgCmVkZ2VzJHNtb290aCA8LSBGQUxTRSAgICAjIHNob3VsZCB0aGUgZWRnZXMgYmUgY3VydmVkPwplZGdlcyRzaGFkb3cgPC0gRkFMU0UKCnZpc25ldDwtdmlzTmV0d29yayhub2RlcyxlZGdlcywgaGVpZ2h0ID0gIjcwMHB4Iiwgd2lkdGggPSAiMTAwJSIsIG1haW49IlRleHQgTmV0d29yayBNb2RlbCIsc3VibWFpbj0gIlVOIFNERyBJbmRpY2F0b3IgTWV0YWRhdGEiLCBmb290ZXI9Ilpvb20gaW4gdG8gc2VlIGluZGljYXRvciBuYW1lLCBjbGljay9ob3ZlciB0byBzZWUgaW5kaWNhdG9yIHRpdGxlIikgJT4lCiAgICB2aXNFZGdlcyhzbW9vdGggPSBGQUxTRSkgJT4lCgogIHZpc09wdGlvbnMoc2VsZWN0ZWRCeSA9ICJHb2FsIiwgCiAgICAgICAgICAgICBoaWdobGlnaHROZWFyZXN0ID0gVFJVRSwgCiAgICAgICAgICAgICBub2Rlc0lkU2VsZWN0aW9uID0gVFJVRSkgIyU+JQogICN2aXNMZWdlbmQobWFpbj0iTGVnZW5kIixwb3NpdGlvbj0icmlnaHQiLCBuY29sPTEpCnZpc25ldAp2aXNTYXZlKHZpc25ldCwgZmlsZSA9ICJUZXh0IE5ldHdvcmsgTW9kZWwuaHRtbCIpCmBgYAojIE5ldHdvcmsgdmlzdWFsaXphdGlvbiB1c2luZyBvdXRwdXQgZnJvbSB0aGUgc29jaWFsIG5ldHdvcmsgbW9kZWwKIyMgSW5kb25lc2lhCiMjI0RhdGEgcHJlcGFyYXRpb24KYGBge3IgaW1wb3J0IEluZG9uZXNpYSBuZXR3b3JrIGNvZWZmaWNpZW50cywgZWNobz1UUlVFLCBldmFsPVRSVUV9CmVkZ2VsaXN0aW5kbyA8LSByZWFkLmNzdigifi9Eb2N1bWVudHMvR2l0SHViL0c1MDU1X1ByYWN0aWN1bV9Qcm9qZWN0Mi9EYXRhL1BDQV9yZXN1bHRzL2luZG9fY29lZmZpY2llbnRzX3NpZy5jc3YiKQojU29tZSBwcmVwcm9jZXNzaW5nCmVkZ2VsaXN0aW5kbzwtZWRnZWxpc3RpbmRvJT4lCiAgc2VsZWN0KFZhcjEsIFZhcjIsIHZhbHVlKSU+JQogIGZpbHRlcihWYXIxIT1WYXIyKQpuYW1lcyhlZGdlbGlzdGluZG8pPC1jKCJmcm9tIiwidG8iLCJ2YWx1ZSIpCmVkZ2VsaXN0aW5kbwpgYGAKRm9yIGZ1dHVyZSBjbGFzc2lmaWNhdGlvbiBvZiBpbmRpY2F0b3JzIGludG8gdGhlIGdvYWxzIHRoZXkgYmVsb25nIHRvLCBjcmVhdGUgdGhlIG5vZGVzIGRhdGFmcmFtZToKYGBge3IgSW5kb25lc2lhIG5vZGVzLCBlY2hvPVRSVUUsIGV2YWw9VFJVRX0KaW5kb25vZGVzIDwtIGVkZ2VsaXN0aW5kbyAlPiUKICBzZWxlY3QoZnJvbSwgdG8pCmluZG9ub2RlcyA8LSBkYXRhLmZyYW1lKEluZGljYXRvciA9IHVubGlzdChpbmRvbm9kZXMsIHVzZS5uYW1lcyA9IEZBTFNFKSkKaW5kb25vZGVzIDwtIGRpc3RpbmN0KGluZG9ub2RlcykKI2luZG9ub2RlcyRnb2FsIDwtIHN0cmlfbWF0Y2hfZmlyc3RfcmVnZXgoaW5kb25vZGVzJGluZGljYXRvciwgIiguKj8pXFwuIilbLDJdCiNpbmRvbm9kZXMkZ29hbCA8LWFzLm51bWVyaWMoaW5kb25vZGVzJGdvYWwpCmluZG9ub2RlczwtbWVyZ2UoeD1pbmRvbm9kZXMseT1pbmRpY2F0b3JfaW5mbyxieT0iSW5kaWNhdG9yIixhbGwueD1UUlVFKQpnMjwtZ3JhcGhfZnJvbV9kYXRhX2ZyYW1lKGVkZ2VsaXN0aW5kbywgZGlyZWN0ZWQ9RkFMU0UsIHZlcnRpY2VzPWluZG9ub2RlcykKaW5fZGVncmVlPC1kZWdyZWUoZzIsIG1vZGU9ImluIikKaW5fZGVncmVlPC1hcy5kYXRhLmZyYW1lKGluX2RlZ3JlZSkKaW5fZGVncmVlIDwtIGNiaW5kKHJvd25hbWVzKGluX2RlZ3JlZSksIGluX2RlZ3JlZSkKcm93bmFtZXMoaW5fZGVncmVlKSA8LSBOVUxMCmNvbG5hbWVzKGluX2RlZ3JlZSkgPC0gYygiSW5kaWNhdG9yIiwiaW5fZGVncmVlIikKaW5kb25vZGVzPC1tZXJnZSh4PWluZG9ub2Rlcyx5PWluX2RlZ3JlZSxieT0iSW5kaWNhdG9yIixhbGwueD1UUlVFKQppbmRvbm9kZXM8LWluZG9ub2RlcyAlPiUKICBhcnJhbmdlKEdvYWwpCmluZG9ub2RlczwtaW5kb25vZGVzICU+JQogIHNlbGVjdChJbmRpY2F0b3IsIEdvYWwsIEluZGljYXRvcl90aXRsZSwgaW5fZGVncmVlKQppbmRvbm9kZXMKaW5kb25vZGVzCmBgYAojIyMgVmlzdWFsaXphdGlvbgpgYGB7ciwgZWNobz1UUlVFLCBldmFsPVRSVUUsIGZpZy5oZWlnaHQ9MTAsIGZpZy53aWR0aD0xMH0KdmlzLm5vZGVzIDwtIGluZG9ub2Rlcwp2aXMubGlua3MgPC0gZWRnZWxpc3RpbmRvCnZpcy5ub2RlcyRzaGFwZSAgPC0gImRvdCIgIAp2aXMubm9kZXMkc2hhZG93IDwtIEZBTFNFICMgTm9kZXMgd2lsbCBkcm9wIHNoYWRvdwp2aXMubm9kZXMkdGl0bGUgIDwtIHZpcy5ub2RlcyRJbmRpY2F0b3JfdGl0bGUgIyBUZXh0IG9uIGNsaWNrCnZpcy5ub2RlcyRsYWJlbCAgPC0gdmlzLm5vZGVzJEluZGljYXRvciAjIE5vZGUgbGFiZWwKdmlzLm5vZGVzJHNpemUgICA8LSB2aXMubm9kZXMkaW5fZGVncmVlICMgTm9kZSBzaXplCiN2aXMubm9kZXMkZ3JvdXAgPC0gdmlzLm5vZGVzJEdvYWwKdmlzLm5vZGVzJGNvbG9yLmJhY2tncm91bmQgPC0gYygiI2VhMWQyZCIsICIjZDE5ZjJhIiwiIzJkOWE0NyIsICIjYzIyMDMzIiwiI2VmNDEyYSIsICIjMDBhZGQ5IiwgIiNmZGI3MTQiLCAiIzhmMTgzOCIsICIjZjM2ZTI0IiwgIiNlMDFhODMiLCAiI2Y5OWQyNSIsICIjY2Q4YjJhIiwgIiM0ODc3M2MiLCAiIzAwN2RiYiIsICIjNDBhZTQ5IiwgICIjMDA1NThhIiwgIiMxYTM2NjgiKVt2aXMubm9kZXMkR29hbF0KdmlzLm5vZGVzJGNvbG9yLmJvcmRlciA8LSBjKCIjZWExZDJkIiwgIiNkMTlmMmEiLCIjMmQ5YTQ3IiwgIiNjMjIwMzMiLCIjZWY0MTJhIiwgIiMwMGFkZDkiLCAiI2ZkYjcxNCIsICIjOGYxODM4IiwgIiNmMzZlMjQiLCAiI2UwMWE4MyIsICIjZjk5ZDI1IiwgIiNjZDhiMmEiLCAiIzQ4NzczYyIsICIjMDA3ZGJiIiwgIiM0MGFlNDkiLCAgIiMwMDU1OGEiLCAiIzFhMzY2OCIpW3Zpcy5ub2RlcyRHb2FsXQp2aXMubm9kZXMkY29sb3IuaGlnaGxpZ2h0LmJhY2tncm91bmQgPC0gYygiI2VhMWQyZCIsICIjZDE5ZjJhIiwiIzJkOWE0NyIsICIjYzIyMDMzIiwiI2VmNDEyYSIsICIjMDBhZGQ5IiwgIiNmZGI3MTQiLCAiIzhmMTgzOCIsICIjZjM2ZTI0IiwgIiNlMDFhODMiLCAiI2Y5OWQyNSIsICIjY2Q4YjJhIiwgIiM0ODc3M2MiLCAiIzAwN2RiYiIsICIjNDBhZTQ5IiwgICIjMDA1NThhIiwgIiMxYTM2NjgiKVt2aXMubm9kZXMkR29hbF0KdmlzLm5vZGVzJGNvbG9yLmhpZ2hsaWdodC5ib3JkZXIgPC0gYygiI2VhMWQyZCIsICIjZDE5ZjJhIiwiIzJkOWE0NyIsICIjYzIyMDMzIiwiI2VmNDEyYSIsICIjMDBhZGQ5IiwgIiNmZGI3MTQiLCAiIzhmMTgzOCIsICIjZjM2ZTI0IiwgIiNlMDFhODMiLCAiI2Y5OWQyNSIsICIjY2Q4YjJhIiwgIiM0ODc3M2MiLCAiIzAwN2RiYiIsICIjNDBhZTQ5IiwgICIjMDA1NThhIiwgIiMxYTM2NjgiKVt2aXMubm9kZXMkR29hbF0KdmlzLmxpbmtzJHdpZHRoIDwtIHZpcy5saW5rcyR2YWx1ZSoxMDAgIyBsaW5lIHdpZHRoCnZpcy5saW5rcyRjb2xvciA8LSAiZ3JheSIgICAgIyBsaW5lIGNvbG9yICAKI3Zpcy5saW5rcyRhcnJvd3MgPC0gIm1pZGRsZSIgIyBhcnJvd3M6ICdmcm9tJywgJ3RvJywgb3IgJ21pZGRsZScKdmlzLmxpbmtzJHNtb290aCA8LSBGQUxTRSAgICAjIHNob3VsZCB0aGUgZWRnZXMgYmUgY3VydmVkPwp2aXMubGlua3Mkc2hhZG93IDwtIEZBTFNFIAp2aXNuZXQ8LXZpc05ldHdvcmsodmlzLm5vZGVzLHZpcy5saW5rcywgaGVpZ2h0ID0gIjcwMHB4Iiwgd2lkdGggPSAiMTAwJSIsIG1haW49IlNvY2lhbCBOZXR3b3JrIE1vZGVsLUluZG9uZXNpYSIsIHN1Ym1haW49IlVOIFNERyBJbmRpY2F0b3IgRGF0YWJhc2UiLGZvb3Rlcj0gIlpvb20gaW4gdG8gc2VlIGluZGljYXRvciBuYW1lLCBjbGljayBvciBob3ZlciB0byBzZWUgaW5kaWNhdG9yIHRpdGxlIikgJT4lCiAgdmlzT3B0aW9ucyhzZWxlY3RlZEJ5ID0gIkdvYWwiLCAKICAgICAgICAgICAgIGhpZ2hsaWdodE5lYXJlc3QgPSBUUlVFLCAKICAgICAgICAgICAgIG5vZGVzSWRTZWxlY3Rpb24gPSBUUlVFKSAjJT4lCiAgI3Zpc0xlZ2VuZChtYWluPSJMZWdlbmQiLCBwb3NpdGlvbj0icmlnaHQiLCBuY29sPTEpCnZpc25ldAp2aXNTYXZlKHZpc25ldCwgZmlsZSA9ICJTb2NpYWwgTmV0d29yayBNb2RlbC1JbmRvbmVzaWEuaHRtbCIpCmBgYAoKIyMgR3VhdGVtYWxhIChOb3QgZmluaXNoZWQpCiMjIyBEYXRhIHByZXBhcmF0aW9uCmBgYHtyIGltcG9ydCBHdWF0ZW1hbGEgbmV0d29yayBjb2VmZmljaWVudHMsIGVjaG89VFJVRSwgZXZhbD1UUlVFfQplZGdlbGlzdGd1YXRlIDwtIHJlYWQuY3N2KCJ+L0RvY3VtZW50cy9HaXRIdWIvRzUwNTVfUHJhY3RpY3VtX1Byb2plY3QyL0RhdGEvUENBX3Jlc3VsdHMvZ3VhX2NvZWZmaWNpZW50c19zaWcuY3N2IikKI1NvbWUgcHJlcHJvY2Vzc2luZwplZGdlbGlzdGd1YXRlPC1lZGdlbGlzdGd1YXRlJT4lCiAgc2VsZWN0KFZhcjEsIFZhcjIsIHZhbHVlKSU+JQogIGZpbHRlcihWYXIxIT1WYXIyKQpuYW1lcyhlZGdlbGlzdGluZG8pPC1jKCJmcm9tIiwidG8iLCJ2YWx1ZSIpCmVkZ2VsaXN0Z3VhdGUKYGBgCiMjIyBWaXN1YWxpemF0aW9uCmBgYHtyIEd1YXRlbWFsYSBub2RlcywgZWNobz1UUlVFLCBldmFsPVRSVUV9Cmd1YXRlbm9kZXMgPC0gZWRnZWxpc3RndWF0ZSAlPiUKICBzZWxlY3QoVmFyMSwgVmFyMikKZ3VhdGVub2RlcyA8LSBkYXRhLmZyYW1lKGluZGljYXRvcm5hbWUgPSB1bmxpc3QoZ3VhdGVub2RlcywgdXNlLm5hbWVzID0gRkFMU0UpKQpndWF0ZW5vZGVzIDwtIGRpc3RpbmN0KGd1YXRlbm9kZXMpCiNndWF0ZW5vZGVzJGdvYWwgPC0gc3RyaV9tYXRjaF9maXJzdF9yZWdleChndWF0ZW5vZGVzJGluZGljYXRvciwgIiguKj8pXFwuIilbLDJdCiNndWF0ZW5vZGVzJGdvYWwgPC1hcy5udW1lcmljKGd1YXRlbm9kZXMkZ29hbCkKZzM8LWdyYXBoX2Zyb21fZGF0YV9mcmFtZShlZGdlbGlzdGd1YXRlLCBkaXJlY3RlZD1GQUxTRSwgdmVydGljZXM9Z3VhdGVub2RlcykKZ3VhdGVub2RlcwpgYGAK